﻿using System;
using System.Diagnostics;
using System.Threading;

namespace NanoMvvm
{
    public class SplashViewModel : WorkspaceViewModel
    {
        private readonly Stopwatch watch;
        private readonly ManualResetEvent mre;
        private Timer timer;
        private int minActiveTime;

        public SplashViewModel()
        {
            watch = new Stopwatch();
            mre = new ManualResetEvent(true);
        }

        /// <summary>
        /// Gets or sets the minimum number of milliseconds the <see cref="SplashViewModel"/> must
        /// remain active before setting IsActive to false. Any such thread is blocked until
        /// the expiration of the MinActiveTime period. Set to 0 to disable effect.
        /// </summary>
        public int MinActiveTime
        {
            get
            {
                return minActiveTime;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("Value must be a number greater than or equal to zero.");
                }

                var elapsed = watch.ElapsedMilliseconds;

                if (IsActive && value > 0 && value > elapsed)
                {
                    if (mre.WaitOne(0))
                    {
                        mre.Reset();
                    }

                    if (timer == null)
                    {
                        timer = new Timer(SignalCallback, mre, value - elapsed, Timeout.Infinite);
                    }
                    else
                    {
                        timer.Change(value - elapsed, Timeout.Infinite);
                    }
                }

                if (IsActive && value == 0 && MinActiveTime > 0)
                {
                    mre.Set();
                    timer.Change(Timeout.Infinite, Timeout.Infinite);
                }

                minActiveTime = value;
            }
        }

        protected override void OnActivation()
        {
            watch.Restart();

            if (MinActiveTime > 0)
            {
                mre.Reset();
                timer = new Timer(SignalCallback, mre, MinActiveTime, Timeout.Infinite);
            }

            base.OnActivation();
        }

        protected override void OnDeactivation()
        {
            mre.WaitOne();

            base.OnDeactivation();
        }

        private static void SignalCallback(object state)
        {
            var mre = (ManualResetEvent)state;

            mre.Set();
        }
    }
}